package cn.amossun.starter.mybatis.data.security.runner;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.amossun.starter.mybatis.data.security.config.MybatisPlusDataSecurityConfig;
import cn.amossun.starter.mybatis.data.security.loader.DecryptRuleCacheLoader;
import cn.amossun.starter.mybatis.data.security.properties.ResultMapConfiguration;
import cn.amossun.starter.mybatis.data.security.rule.MybatisDecryptRule;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @description: 解密规则本地缓存执行器
 * @author: Amos.Sun
 * @DateTime: 2020/03/16 15:02
 **/
@Slf4j
@Data
public class DecryptRuleLocalCacheRunner implements LocalCacheRunner {

    private final MybatisDecryptRule mybatisDecryptRule;

    private final LoadingCache<String, Object> loadingCache;

    private final OrmConfigCacheRunner ormConfigCacheRunner;

    public DecryptRuleLocalCacheRunner(MybatisPlusDataSecurityConfig mybatisConfig,
                                       MybatisDecryptRule mybatisDecryptRule,
                                       DecryptRuleCacheLoader decryptRuleCacheLoader,
                                       OrmConfigCacheRunner ormConfigCacheRunner) {
        this.mybatisDecryptRule = mybatisDecryptRule;
        this.ormConfigCacheRunner = ormConfigCacheRunner;
        this.loadingCache = CacheBuilder.newBuilder()
                .maximumSize(mybatisConfig.getMybatisPlus().getCache().getMaximumSize())
                .refreshAfterWrite(mybatisConfig.getMybatisPlus().getCache().getDuration(), TimeUnit.SECONDS)
                .build(decryptRuleCacheLoader);
    }

    @Override
    public void initCache() throws Exception {
        log.info("DecryptRuleLocalCacheRunner加载数据中.");
        //启动初始化Class缓存.
        Object object = ormConfigCacheRunner.getCacheValue();
        if(object == null || !(object instanceof Optional)) {
            return;
        }
        Optional<Object> optionalObject = (Optional<Object>)object;
        if(!optionalObject.isPresent()) {
            log.warn("获取redis加解密配置为空.");
            return;
        }
        JSONArray jsonArray = JSONUtil.parseArray(JSONUtil.toJsonStr(optionalObject.get()));
        List<ResultMapConfiguration> ormConfigs = JSONUtil.toList(jsonArray, ResultMapConfiguration.class);
        if(CollectionUtil.isEmpty(ormConfigs)) {
            log.warn("获取redis加解密配置json数组为空.");
            return;
        }
        log.info("获取redis加解密配置json {} 个.", ormConfigs.size());
        if(refreshLocalCache(ormConfigs)) {
            log.info("DecryptRuleLocalCacheRunner加载数据至GuavaCache: {}", optionalObject.isPresent() ? JSONUtil.toJsonStr(optionalObject.get()) : null);
        }

    }

    @Override
    public LoadingCache<String, Object> getLoadingCache() {
        return this.loadingCache;
    }

    @Override
    public boolean refreshLocalCache(List<ResultMapConfiguration> ormConfigs) throws Exception {
        if(CollectionUtil.isEmpty(ormConfigs)) {
            return false;
        }
        for(ResultMapConfiguration resultMapConfiguration : ormConfigs) {
            if(ObjectUtil.isNotEmpty(resultMapConfiguration) && StrUtil.isNotEmpty(resultMapConfiguration.getObjectClassName())) {
                getLoadingCache().get(resultMapConfiguration.getObjectClassName());
            }
        }
        return true;
    }
}
